/**
 * Handles the opening, closing of a given posting.  Subclasses the jsx3.gui.Tab class, since the postings
 * will be displayed within a tabbed pane.
 * @author birdeau@yahoo.com
 */
jsx3.require("jsx3.gui.Tab");
jsx3.lang.Class.defineClass("gicx.Posting", jsx3.gui.Tab, [], function(Posting,Posting_prototype) {


  //used to parse the domain (i.e., sfbay) and the posting id from a given posting page URL
  var myPostingReg = /http:\/\/([^\.]*)\.craigslist\.org[^0-9]*(\d*)/i;


  //url for 'close tab' icon that appears next to the tab label
  Posting.REM_IMG_URL = gicx.APP.resolveURI("images/close_off.gif");
  Posting.REM_IMG_URL_ON = gicx.APP.resolveURI("images/close_on.gif");


  /**
   * main method
   */
  Posting_prototype.init = function() {
    //override the url composite for the class; just use this one if passed
    this.jsxsuper();
  };


  /**
   * Opens the posting defined by the CDF record, objEvent.target. Called when the user has chosen to view a blocked, favorited, or search results item.
   * @param objRecord {jsx3.xml.Entity}
   * @param b2Pass {Boolean} The tab that holds a posting is always opened immediately.  If not content exists yet, the 2pass is called when the content arrives
   */
  Posting.open = function(objRecord,b2Pass) {
    //exit early if the posting is already open
    var objReader = gicx.APP.getJSXByName("tpReader");
    var strRecordId = objRecord.getAttribute("jsxid");

    if(!b2Pass) {
      //make sure no duplicates are allowed to be opened
      for(var i=0;i<objReader.getChildren().length;i++) {
        if(strRecordId == objReader.getChild(i).postingurl) {
          jsx3.log('Posting already open in reader pane: ' + strRecordId);
          objReader.getChild(i).doShow();
          return;
        }
      }

    }

      //check the hard and soft caches for the posting. If a copy is there, use that one; it will be the most up-to-date with any user annotations
      var bCached = false;
      var objCachedRecord = gicx.Cache.getRecord("searchHistory",strRecordId);
      if(!objCachedRecord) {
        objCachedRecord = gicx.Cache.getRecord("_searchHistory",strRecordId);
        //since the record was neither in the soft nor hard caches, place it in the soft cache. If the user favorites it, it will be moved to the hard cache
        if(!objCachedRecord)
          gicx.Cache.setRecord("_searchHistory",objRecord);
      }
      if(objCachedRecord instanceof jsx3.xml.Entity) objRecord = objCachedRecord;


    //display the posting in the reader; if in pipes mode, use an iframe (since pipes mode is x-domain-safe). There's no access to the posting content
    //but it scales well (yahoo as transport) and it guarantess x-domain access without a proxy server (yahoo pipes is the proxy)
    if(gicx.APP.getEnv("pipes") == "pipes") {
      //running in 'safe' mode. use an iframe to display the full posting (browser security won't allow access to the posting content)
      var strMyContent = Posting.getIframe(strRecordId);
      var intOverflow = 2;
    } else {
      //check if the record has any content; if not, asychronously fetch its content from craigslist (this is the actual posting) and then exit early
      var strContent = objRecord.getAttribute("content");
      if(jsx3.util.strEmpty(strContent)) {
        //asynchronously fetch the given page and scrape the content
        var objHttp = new gicx.Query();
        objHttp.setURL(strRecordId);
        objHttp.openForPage(true);
        objHttp.subscribe(jsx3.net.Request.EVENT_ON_RESPONSE,function(objEvent) {
          var objFilter = new gicx.Filter(objHttp.getResponseText());
          strContent = objFilter.getBody()
          if(strContent && strContent.length) {
            objRecord.setAttribute("content",strContent[1]);
            objRecord.setAttribute("header",strContent[0]);
            Posting.open(objRecord,true);
          }
        });
        //firefox can return so quickly that the same call stack is run, causing a race condition; manually break the stack
        jsx3.sleep(function() { objHttp.send(); });
      }

      //if content was found, continue
      if(strContent) {
        //the first time a posting is viewed in the reader, auto-scan it for phone, email, and address information
        if(objRecord.getAttribute("validated") != "1") {
          objRecord.setAttribute("validated","1");
          //scan the posting for email, phone, address
          var strContent = objRecord.getAttribute("content");
          var objFilter = new gicx.Filter(strContent);

          //get the phones
          var objItems = objFilter.getPhones();
          for(var i=0;i<objItems.length-1  && i < 4;i++) {
            var objNode = objRecord.createNode(jsx3.xml.Entity.TYPEELEMENT,"phone");
            objRecord.appendChild(objNode);
            objNode.setAttribute("jsxid",objItems[i]+"");
          }

          //get emails
          var objItems = objFilter.getEmails();
          for(var i=0;i<objItems.length  && i < 4;i++) {
            var objNode = objRecord.createNode(jsx3.xml.Entity.TYPEELEMENT,"email");
            objRecord.appendChild(objNode);
            objNode.setAttribute("jsxid",objItems[i]+"");
          }

          //is there a more accurate address
          var strLoc = objFilter.getAddress();
          if(strLoc)
            objRecord.setAttribute("loc",strLoc);
        }

        //append the header (hidden) to the content; user can toggle to view the header as needed
        var strMyContent = '<div style="display:none;padding-bottom:8px;">' + objRecord.getAttribute("header") + '</div>' + strContent;
        var intOverflow = 1;
      } else {
        //NOT running in safe mode, but for some reason the content could not be resolved. use an iframe as a backup in order to make sure the content is shown
        var strMyContent = "loading <a target='new' href='" + strRecordId + "'>" + strRecordId + "</a>";
        var intOverflow = 1;
      }
    }

    //make room for the reader pane if it's not yet been openened (if this is the first posting to be opened)
    var objSplitter = gicx.APP.getJSXByName("spltMain");
    if(objSplitter.getSubcontainer1Pct() == "100%") {
      var objBody = gicx.APP.getBodyBlock();
      var intW = objBody.getAbsolutePosition().W;
      objSplitter.setSubcontainer1Pct("40%",true);
    }

    //set the label on the tab
    if(b2Pass) {
      var objTab = objReader.getChild(strRecordId);
      if(objTab) {
        objTab.getDescendantOfName("blkPosting").setText(strMyContent).repaint();
        gicx.publish({subject:"POSTING_WAS_ACTIVATED",target:objTab});
      }
    } else {
      var objTab = objReader.loadAndCache("components/tab_reader.xml",false);
      objTab.postingurl = strRecordId;
      objTab.setName(strRecordId);
      var strRemImage = '<img onmouseout="this.src=\'' + Posting.REM_IMG_URL + '\';" onmouseover="this.src=\'' + Posting.REM_IMG_URL_ON + '\';" src="' + Posting.REM_IMG_URL + '" style="width:11px;height:11px;cursor:pointer;vertical-align:bottom;" title="Close posting" onclick="gicx.Posting.close(jsx3.html.getJSXParent(this).postingurl);"/>';
      var strTitle = objRecord.getAttribute("jsxtext");
      var strTruncated = jsx3.util.strTruncate(strTitle, 20,'...',.5);
      objTab.setText('<div style="white-space:no-wrap;">' + strRemImage + '&#160;<span title="' + strTitle.replace('"',"'") + '">' + strTruncated  + '</span></div>');
      objTab.getDescendantOfName("blkPosting").setOverflow(intOverflow);
      objTab.getDescendantOfName("blkPosting").setText(strMyContent);
      objReader.paintChild(objTab);
      //show the new tab
      objTab.doShow();
      gicx.publish({subject:"POSTING_WAS_OPENED",target:objTab,uri:strRecordId,title:strTitle});
    }
  };


  /**
   * Gets the markup for an iframe that when embedded in the page will load the given posting
   * @param strSrc {String} URL for the cl posting to display in the iframe
   * @returns {String} HTML markup
   */
  Posting.getIframe = function(strSrc) {
    return '<iframe src="' + strSrc + '" border="none" style="width:100%;height:100%;border:solid 1px #000000;background-color:#efeff0;"></iframe>';
  };


  /**
   * Toggles the display of the original posting header
   */
  Posting.toggleHeader = function() {
    if(!(gicx.APP.getEnv("pipes") == "pipes")) {
      var objHeader = Posting.getActive().getDescendantOfName("blkPosting").getRendered().childNodes[0];
      objHeader.style.display = (objHeader.style.display=="none")?"":"none";
    }
  };


  /**
   * Gets the active posting container
   * @returns {jsx3.gui.Tab}
   */
  Posting.getActive = function() {
    var objReader = gicx.APP.getJSXByName("tpReader");
    return (objReader.getChildren().length) ? objReader.getChild(objReader.getSelectedIndex()) : null;
  };


  /**
   * Toggles which addin module (contact or audit) is active for the posting. TODO: in future want to
   * make this a generic extension point for the application and take advantage of the public pagebus.
   * @returns {jsx3.gui.Tab}
   */
  Posting.toggle = function(objOn,objOff,intIndex) {
    gicx.APP.getJSXByName("tpTools").getChild(intIndex).doShow();
    objOn.setClassName("active_tool_link").repaint();
    objOff.setClassName("inactive_tool_link").repaint();
  }


  /**
   * Gets the active posting record. The hard cache is first checked and then the soft cache
   * @returns {jsx3.xml.Entity}
   */
  Posting.getActiveRecord = function() {
    if(Posting.getActive()) {
      var strURL = Posting.getActive().postingurl;
      //check the hard cache
      var objRecord = gicx.Cache.getRecord("searchHistory",strURL);
      if(!objRecord)
        objRecord =  gicx.Cache.getRecord("_searchHistory",strURL);
      if(!objRecord)
        objRecord = gicx.getResultsTable().getRecordNode(strURL);
    }
    return (objRecord)
  };


  /**
   * Opens the original posting at craigslist.org in a new browser window
   * @param strId {String}
   */
  Posting.openLegacy = function(strId) {
    window.open(strId);
  };


  /**
   * Saves the posting to the user's favorites
   * @param strId {String}
   */
  Posting.favorite = function(strId) {
    //check the soft cache
    var objRecord = gicx.Cache.getRecord("_searchHistory",strId);

    //check the search results
    if(!objRecord)
      objRecord = gicx.getResultsTable().getRecordNode(strId);

    if(objRecord) {
      //var strId = objRecord.getAttribute("jsxid");
      objCachedRecord = gicx.Cache.getRecord("searchHistory",strId);
      if(objCachedRecord) {
        jsx3.log('Already a favorite: ' + strId);
      } else {
        jsx3.log('Adding to favorites: ' + strId);
        objRecord.setAttribute("isfavorited","1");
        var objRecordParent = gicx.Cache.getDocument("searchHistory").selectSingleNode("//favorites");
        objReturn = gicx.Cache.setRecord("searchHistory", objRecord, objRecordParent);
        gicx.publish({subject:"POSTING_WAS_FAVORITED",target:objReturn,uri:strId});
        return true;
      }
    }
  };


  /**
   * Removes the posting from the user's favorites
   * @param strId {String}
   */
  Posting.unfavorite = function(strId) {
    var objDeletedFavorite = gicx.Cache.deleteRecord("searchHistory",strId);
    if(objDeletedFavorite) {
      //object was in the hard cache, but has now been removed; must now put in the soft cache
      gicx.Cache.setRecord("_searchHistory",objDeletedFavorite);
      gicx.publish({subject:"POSTING_WAS_UNFAVORITED",target:objDeletedFavorite,uri:strId});
    }
  };


  /**
   * Saves the posting to the user's list of blocked postings
   * @param strId {String}
   */
  Posting.block = function(strId) {
    //check the soft cache
    var objRecord = gicx.Cache.getRecord("_searchHistory",strId);

    //check the search results
    if(!objRecord)
      objRecord = gicx.getResultsTable().getRecordNode(strId);

    if(objRecord) {
      //var strId = objRecord.getAttribute("jsxid");
      objCachedRecord = gicx.Cache.getRecord("searchHistory",strId);
      if(objCachedRecord) {
        jsx3.log('Already in history; shouldnt be allowed to block a favorite; fix this: ' + strId);
      } else {
        jsx3.log('Adding to blocked: ' + strId);
        //add this posting to the list of blocked postings; remove its cached content to save space
        objRecord.removeAttribute("content");
        objRecord.removeChildren();
        var objRecordParent = gicx.Cache.getDocument("searchHistory").selectSingleNode("//blocked");
        objReturn = gicx.Cache.setRecord("searchHistory", objRecord, objRecordParent);
        Posting.close(strId);
        gicx.publish({subject:"POSTING_WAS_BLOCKED",target:objReturn,uri:strId});
        return true;
      }
    }
  };


  /**
   * Removes the posting from the user's list of blocked postings
   * @param strId {String}
   */
  Posting.unblock = function(strId) {
    var objDeletedBlock = gicx.Cache.deleteRecord("searchHistory",strId);
    if(objDeletedBlock) {
      //object was in the hard cache, but has now been removed; must now put in the soft cache
      gicx.Cache.setRecord("_searchHistory",objDeletedBlock);
      gicx.publish({subject:"POSTING_WAS_UNBLOCKED",target:objDeletedBlock,uri:strId});
    }
  };


  /**
   * Called by context menu selection. Performs an action on the selected rows in the search results table
   * @param strAction {String} one of: open, save, show, hide, block
   */
  Posting.onMenu = function(strAction) {
    //resolve the postingurl (the posting id) as well as the subdomain (region)
    var objTable = gicx.getResultsTable();
    var objRecords = objTable.getSelectedNodes().iterator();

    switch (strAction){
      case "open":
        while(objRecords.hasNext()) Posting.open(objRecords.next());
        break;
      case "save":
        while(objRecords.hasNext()) Posting.favorite(objRecords.next().getAttribute("jsxid"));
        break;
      case "show":
        while(objRecords.hasNext()) gicx.prefetchContent(objTable,objRecords.next().getAttribute("jsxid"))
        break;
      case "hide":
        while(objRecords.hasNext()) gicx.hideCachedImages(objTable,objRecords.next().getAttribute("jsxid"))
        break;
      case "block":
        while(objRecords.hasNext()) Posting.block(objRecords.next().getAttribute("jsxid"));
    }
  };


  /**
   * Emails this posting to the email address defined in 'my settings'.
   * @param strId {String}
   */
  Posting.emailFriend = function(strId) {
    //resolve the postingurl (the posting id) as well as the subdomain (region)
    myPostingReg.exec(strId);
    var strPostingRegion = RegExp.$1;
    var strPostingId = RegExp.$2;

    var objQ = new gicx.Query('ocp');
    var defaultemail = gicx.Cache.getRecord("preferences","email").getAttribute("value");
    gicx.Query.DEFAULT_FRIEND_FORM.email = defaultemail;
    gicx.Query.DEFAULT_FRIEND_FORM.rcptAddress = defaultemail;
    objQ.setRegion(strPostingRegion);
    objQ.setPostingId(strPostingId);
    objQ.openForFriend(true);
    objQ.subscribe(jsx3.net.Request.EVENT_ON_RESPONSE,Posting.emailFriendCB);
    objQ.send();
  };


  /**
   * After an email notification is sent and the server has responded, this message is called to alert the user of the success
   * @param objEvent {Object} named field: target (the jsx3.net.Request instance)
   */
  Posting.emailFriendCB = function(objEvent) {
    var objHttp = objEvent.target;
    var objEmailWasSent = gicx.APP.getBodyBlock().loadAndCache("components/email_was_sent.xml",false);
    objEmailWasSent.getChild("msg").setText("Posting was emailed to <br/><b>" + gicx.Cache.getRecord("preferences","email").getAttribute("value") + "</b><div style=\"padding-top:5px;\"><i>Choose 'My Preferences' to update</i></div>");
    gicx.APP.getBodyBlock().paintChild(objEmailWasSent);
    window.setTimeout(function() { objEmailWasSent.getParent().removeChild(objEmailWasSent);},2500);
  };


  /**
   * Closes the given posting container. Resets the reader pane width to 0px if no postings left open
   * @param strId {String}
   */
  Posting.close = function(strId) {
    //resolve which posting to close; the name of the tab that holds the posting is the posting id, so easy to resolve calling 'getChild'
    var objParent = gicx.APP.getJSXByName("tpReader");
    objJSX = objParent.getChild(strId);
    if(objJSX) {
      objParent.removeChild(objJSX);
      gicx.publish({subject:"POSTING_WAS_CLOSED",target:objJSX,uri:strId});

      //TODO: move to main?  subscribe on init to the closed event and run the following
      if(!objParent.getChildren().length) {
        var objSplitter = gicx.APP.getJSXByName("spltMain");
        objSplitter.setSubcontainer1Pct("100%",true);
      }
    }
  };


  /**
   * Subscribed to the POSTING_WAS_OPENED event; adds a menu item to the list of all open postings; useful when number of tabs is too large
   * to see all tabs.  Similar to Firefox which provides a menu of all open tabs.
   * @param objEvent {Object} with named fields:  uri,title
   */
  Posting.addMenuItem = function(objEvent) {
    var objXML = gicx.APP.getCache().getDocument("open_postings");
    if(!objXML)
      gicx.APP.getCache().setDocument("open_postings",jsx3.xml.CDF.Document.newDocument());
    var objNode = objXML.selectSingleNode("//record[@jsxid='" + objEvent.uri +"']");
    if(!objNode) {
      objNode = objXML.createNode(jsx3.xml.Entity.TYPEELEMENT,"record");
      objXML.getRootNode().appendChild(objNode);
      objNode.setAttribute("jsxid",objEvent.uri);
      objNode.setAttribute("jsxtext",jsx3.util.strTruncate(objEvent.title, 40,'...',.5));
      objNode.setAttribute("jsxtip",objEvent.title);
    }
  };


  /**
   * Subscribed to the POSTING_WAS_CLOSED event; adds a menu item to the list of all open postings; useful when number of tabs is too large
   * to see all tabs.  Similar to Firefox which provides a menu of all open tabs.
   * @param objEvent {Object} with named fields:  uri
   */
  Posting.removeMenuItem = function(objEvent) {
    var objXML = gicx.APP.getCache().getDocument("open_postings");
    if(objXML) {
      var objNode = objXML.selectSingleNode("//record[@jsxid='" + objEvent.uri +"']");
      if(objNode)
        objNode.getParent().removeChild(objNode);
    }
  };

});

//subscribe handler functions to relevant system events
gicx.APP.subscribe("POSTING_WAS_OPENED",gicx.Posting.addMenuItem);
gicx.APP.subscribe("POSTING_WAS_CLOSED",gicx.Posting.removeMenuItem);



